//Modificado por Ruben, En el metodo LU estoy sobreescribiendo la matris resultado, asi que vuelvan a leerlo cuando usen su metodo;
//Ahora pide el nombre de los archivos a resolver para no tener que estar borrando siempre los que ya tenemos.
//Matriz_in: es el sistema de ecuaciones, Vector_out: es el resultado del sistema
//Ya casi esta listo.
//FLISOL 2011 ITCelaya @rnstt
//Por fin

import java.io.*;
import java.util.Scanner;
class Metodos {

	public static void main(String ... args ) throws IOException {
		Matris m = new Matris();

		if(args.length == 2)
			m.leerMatris(args[0], args[1]);
		else
			m.leerMatris("MatrisA.txt", "ResultadoMatrisA.txt");

		//m.imprimirMatris();
		m.gaussSeidel();
	}
}


class Matris{

	private double matris [][];
	private double matrisResultado [];
	private int vars [];
	
	
	Matris(){
	}


	void LU(){
		int tam=matris.length; double sumatoria=0,mx=0,mn;
		double [][]L=matris;
		double factor;

		//Se calcula el L*U en una sola matriz
		for (int k = 0; k <= tam - 2; k++) {
			for (int i =  k+1; i < tam; i++) {
				factor = L[i][k]/L[k][k];
				L[i][k] = factor;
				for (int j = k+1; j < tam; j++)
					L[i][j] -= factor * L[k][j];
			}
		}
		
		// Se hace una sustitucion hacia adelante
		sumatoria = 0;
		for (int k = 0; k < tam; k++) {
			for (int j = 0; j < k; j++) {
				sumatoria= sumatoria + L[k][j]*matrisResultado[j];		
			}
			matrisResultado[k] =matrisResultado[k] - sumatoria;		
			sumatoria=0;
		}

		//Se hace una sustitucion hacia atras
		for (int k = tam-1; k >=0; k--) {
			for (int j = k+1; j <tam; j++) {
				sumatoria= sumatoria + L[k][j]*matrisResultado[j];		
			}
			matrisResultado[k] =(matrisResultado[k] - sumatoria)/L[k][k];		
			sumatoria=0;
		}

		//Se imprime el resultado
		System.out.println("Resuelta por LU");
		for(int i=0;i<matrisResultado.length;i++)
			System.out.println("X"+i+" = "+matrisResultado[i]);
	}

			
			
	void gaussSeidel(){
		final double VECTOR_INICIAL = 0;
		final double ERROR = .001;

		double m [][] = matris;
		double R [] = matrisResultado;
		int tam = m.length;
		double x [] = new double[ tam ];
		double oldX [] =new double[ tam ];

		//asignar los valores de vector inicial a las x's
		for( int y = 0; y < tam ; y++ ){
			x [y] = VECTOR_INICIAL;
			oldX [y] = VECTOR_INICIAL;
		}

		boolean salir = false;

		while( !salir ){
			//calcular x's
			for(int i = 0; i < tam ; i++){
				x[i] = R[i];
				for(int j = 0 ; j < tam ; j++){
					if( j != i ){
						x[i] -= ( m[i][j] * x[j] );
					}
				}
				x[i] = (x[i]) / m[i][i];
			}

			//caclcular errores
			int control=0;
			for(int u = 0 ; u < tam ; u ++){
				control++;
				double e = Math.abs((x[u] - oldX[u])/x[u])*100;
				//System.out.println("e= "+e);

				//En caso de que la funcion no tenga solucion debemos poner un limite por que si no se cicla.
				if((e < ERROR)||control>10000 )
					salir = true;
			}			
			

			//guardar valores actuales en old
			int cont = 0;
			for(double xn : x)
				oldX[cont++] = xn;
		
		}//while principal

		//imrpmir solucion
		int cont = 1;
		for(double xn : x){
			System.out.println("x["+(cont++)+"] = " +xn);
		}

	}//gauss seidel

	void imprimirMatris(){
		
		for(int x = 0; x < matris.length ;  x++){
			System.out.print("[ ");
			for(int y = 0; y < matris[x].length ;  y++){
				System.out.print( matris[x][y]+ " " );
			}	
			System.out.print("] = [ " + matrisResultado[x] + " ]" );
			System.out.println(  );
		}
	}


	void leerMatris(String MA, String MAR) throws IOException{
		String m = "";


		BufferedReader cin = new BufferedReader(new FileReader(MA));

		int row = 0;
		int col = 0;
		String linea = "";
		while((linea=cin.readLine()) != null){
			
			for(String num : linea.split(" ")){

				//definir la matriz
				if( matris == null )
					matris = new double[linea.split(" ").length][linea.split(" ").length];

				matris [col] [row] = Double.parseDouble(num);
				col++;
			}
			col = 0;
			row++;
		}

		cin = new BufferedReader(new FileReader( MAR ));
		matrisResultado = new double [ matris.length ];


		int flag = 0;
		for(String res : cin.readLine().split(" ")){

			matrisResultado[flag++] = Double.parseDouble( res );
		}

		System.out.println( "done reading file" );

	}//leerMatris

}//clase Matris
